package com.stark.commons.spring.web.interceptor;

import java.net.URLDecoder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.core.NamedThreadLocal;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 性能监控拦截器。
 * <p>计算从拦截到请求到响应完成消耗的时间，当消耗时间大于标准时间 {@link #standard} 时以 WARN 级别记录日志。
 * @author Ben
 * @since 1.0.0
 * @version 1.0.0
 */
@NoArgsConstructor
@RequiredArgsConstructor
@Slf4j
public class MonitorInterceptor extends HandlerInterceptorAdapter {
	
	private NamedThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<>("Monitor start time");
	
	@NonNull
	private Long standard;
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		if (handler.getClass().isAssignableFrom(HandlerMethod.class)) {
			long beginTime = System.currentTimeMillis();
	        startTimeThreadLocal.set(beginTime);
		}
        return true;
	}
	
	@Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) throws Exception {  
		if (handler.getClass().isAssignableFrom(HandlerMethod.class)) {
	        long startTime = startTimeThreadLocal.get();
	        long endTime = System.currentTimeMillis();
	        long diff = endTime - startTime;
	        
	        if (standard == null || diff > standard) {
	        	String consume;
		        if (diff < 1000) {
		        	consume = diff + "ms";
		        } else if (diff < 1000 * 60) {
		        	consume = String.format("%.2f", 1.0 * diff / 1000) + "s";
		        } else if (diff < 1000 * 60 * 60) {
		        	consume = String.format("%.2f", 1.0 * diff / 1000 / 60) + "m";
		        } else {
		        	consume = String.format("%.2f", 1.0 * diff / 1000 / 60 / 60) + "h";
		        }
		        
	        	log.warn("{} \"{}\" consume {}",
	        			request.getMethod(),
	        			request.getRequestURI() + (StringUtils.isBlank(request.getQueryString()) ? "" : "?" + URLDecoder.decode(request.getQueryString(), "UTF-8")),
	        			consume);
	        }
		}
    }
	
}
